package com.xnyzc.lhy.nio.netty;

import com.xnyzc.lhy.common.constant.ExceptionConstant;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

/**
 * Netty启动服务
 *
 * @author liuju
 * @create 2019-07-17 13:23
 */
@Slf4j
@Component
public class NettyServer {

    @Value("${netty.port}")
    private Integer nettyPort;

    /**
     * 监测读操作空闲时间
     */
    private final static int READER_IDLE_TIME_SECONDS = 10;

    /**
     * 监测写操作空闲时间
     */
    private final static int WRITER_IDLE_TIME_SECONDS = 10;

    /**
     * 监测读写全部空闲时间
     */
    private final static int ALL_IDLE_TIME_SECONDS = 30;

    @Autowired
    private ServerHandler serverHandler;

    public void run() {
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup);
            bootstrap.channel(NioServerSocketChannel.class);
            bootstrap.option(ChannelOption.SO_BACKLOG, 1024);
            // 使消息立即发出去，不用等待到一定的数据量才发出去
            bootstrap.option(ChannelOption.TCP_NODELAY, true);
            // 保持长连接状态
            bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true);
            bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
                @Override
                protected void initChannel(SocketChannel socketChannel) throws Exception {
                    ChannelPipeline pipeline = socketChannel.pipeline();
                    pipeline.addLast("ping", new IdleStateHandler(READER_IDLE_TIME_SECONDS, WRITER_IDLE_TIME_SECONDS,
                            ALL_IDLE_TIME_SECONDS, TimeUnit.SECONDS));
                    pipeline.addLast("decoder", new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
                    pipeline.addLast("encoder", new LengthFieldPrepender(4));
                    pipeline.addLast(serverHandler);
                }
            });
            ChannelFuture channelFuture = bootstrap.bind(nettyPort).sync();
            if (channelFuture.isSuccess()) {
                log.info(ExceptionConstant.NETTY_START_SUCCESS+",端口号：{}",nettyPort);
            }
            // 监听服务器关闭监听
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            log.error(ExceptionConstant.NETTY_START_FAIL,": {}",e);
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }
}
